
local unicodedata = require 'dclm.text.unicodedata'
local itercache = require 'dclm.cache.iterator'

local Tests = io.open('NormalizationTest.txt', 'r')

local fields = string.rep('(.-);', 5)

local function iter_aux(v)
  for i = 1, #v do
    coroutine.yield(v[i])
  end
end

local function iter(v)
  return itercache.get(iter_aux, v)
end

local function split(v)
  local t = {}
  for s in v:gmatch('%S+') do
    t[#t+1] = tonumber(s,16)
  end
  return t
end

local function make_nfc(v)
  local t = {}
  for c in unicodedata.eachcompose(unicodedata.eachdecompose(false, iter(v))) do
    t[#t+1] = c
  end
  return t
end

local function make_nfkc(v)
  local t = {}
  for c in unicodedata.eachcompose(unicodedata.eachdecompose(true, iter(v))) do
    t[#t+1] = c
  end
  return t
end

local function make_nfd(v)
  local t = {}
  for c in unicodedata.eachdecompose(false, iter(v)) do
    t[#t+1] = c
  end
  return t
end

local function make_nfkd(v)
  local t = {}
  for c in unicodedata.eachdecompose(true, iter(v)) do
    t[#t+1] = c
  end
  return t
end

local function bert(g)
  local s = ''
  for i = 1, #g do
    s = s .. string.format('U+%04X ', g[i])
  end
  return s
end

local function identical(prefix,line,t1,t2)
    for i = 1, math.max(#t1, #t2) do
      if (t1[i] ~= t2[i]) then
        print("[Line " .. line .. "] " .. prefix .. " EXPECT:(" .. bert(t1) .. ') GOT:(' .. bert(t2) .. ')')
        break
      end
    end
end

local i = 1

local line_no = 0

for l in Tests:lines() do
  line_no = line_no + 1
  l = l:gsub('#.*', '')
  local test_s,nfc_s,nfd_s,nfkc_s,nfkd_s = l:match(fields)
  if test_s then
    local test,nfc,nfd,nfkc,nfkd = split(test_s),split(nfc_s),split(nfd_s),split(nfkc_s),split(nfkd_s)
    
    identical('c2 == NFC(c1)', line_no, nfc, make_nfc(test))
    identical('c2 == NFC(c2)', line_no, nfc, make_nfc(nfc))
    identical('c2 == NFC(c3)', line_no, nfc, make_nfc(nfd))
    identical('c4 == NFC(c4)', line_no, nfkc, make_nfc(nfkc))
    identical('c4 == NFC(c5)', line_no, nfkc, make_nfc(nfkd))
    
    identical('c3 == NFD(c1)', line_no, nfd, make_nfd(test))
    identical('c3 == NFD(c2)', line_no, nfd, make_nfd(nfc))
    identical('c3 == NFD(c3)', line_no, nfd, make_nfd(nfd))
    identical('c5 == NFD(c4)', line_no, nfkd, make_nfd(nfkc))
    identical('c5 == NFD(c5)', line_no, nfkd, make_nfd(nfkd))
    
    identical('c4 == NFKC(c1)', line_no, nfkc, make_nfkc(test))
    identical('c4 == NFKC(c2)', line_no, nfkc, make_nfkc(nfc))
    identical('c4 == NFKC(c3)', line_no, nfkc, make_nfkc(nfd))
    identical('c4 == NFKC(c4)', line_no, nfkc, make_nfkc(nfkc))
    identical('c4 == NFKC(c5)', line_no, nfkc, make_nfkc(nfkd))
    
    identical('c5 == NFKD(c1)', line_no, nfkd, make_nfkd(test))
    identical('c5 == NFKD(c2)', line_no, nfkd, make_nfkd(nfc))
    identical('c5 == NFKD(c3)', line_no, nfkd, make_nfkd(nfd))
    identical('c5 == NFKD(c4)', line_no, nfkd, make_nfkd(nfkc))
    identical('c5 == NFKD(c5)', line_no, nfkd, make_nfkd(nfkd))
    
    i = i + 1
  end
end
